<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="JDxMv" id="JDxMv"><span data-lake-id="ua17f81ba" id="ua17f81ba">典型回答</span></h1>
  <p data-lake-id="udb47acd1" id="udb47acd1"><br></p>
  <p data-lake-id="ub67b2102" id="ub67b2102"><span data-lake-id="u3f3aeb38" id="u3f3aeb38">本文重点说一说在Java应用中，多级缓存如何实现。</span></p>
  <p data-lake-id="u6607c33b" id="u6607c33b"><span data-lake-id="u29969400" id="u29969400">​</span><br></p>
  <p data-lake-id="ubb800cb0" id="ubb800cb0"><span data-lake-id="uf24b65f3" id="uf24b65f3">多级缓存是比较常见的一种性能优化的手段，一般来说就是本地缓存+分布式缓存。</span></p>
  <p data-lake-id="u7929b4f6" id="u7929b4f6"><span data-lake-id="u4b899c44" id="u4b899c44">​</span><br></p>
  <p data-lake-id="ua53e0a06" id="ua53e0a06"><span data-lake-id="u2347c76e" id="u2347c76e">本地缓存一般采用Caffeine和Guava，这两种是性能比较高的本地缓存的框架。他们都提供了缓存的过期、管理等功能。</span></p>
  <p data-lake-id="uca650158" id="uca650158"><span data-lake-id="u2c10f7b6" id="u2c10f7b6">​</span><br></p>
  <p data-lake-id="u5405eb1d" id="u5405eb1d"><span data-lake-id="u5305f1f7" id="u5305f1f7">分布式缓存一般采用Redis、Memcached等分布式缓存框架。</span></p>
  <p data-lake-id="u79a86324" id="u79a86324"><span data-lake-id="u67744755" id="u67744755">​</span><br></p>
  <p data-lake-id="u2c090c3b" id="u2c090c3b"><span data-lake-id="u991a0e80" id="u991a0e80">在做多级缓存的方案中，会先查询本地缓存，如果本地缓存查不到，再查询分布式缓存。并且在分布式缓存中查询到之后保存到本地缓存中一份。</span></p>
  <p data-lake-id="u8148906f" id="u8148906f"><span data-lake-id="ucea53e78" id="ucea53e78">​</span><br></p>
  <p data-lake-id="u794b3242" id="u794b3242" style="text-align: center"><img src="https://cdn.nlark.com/yuque/0/2023/png/5378072/1690547117195-6af0bb11-aa25-4013-a02a-4f583a717cd6.png?x-oss-process=image%2Fwatermark%2Ctype_d3F5LW1pY3JvaGVp%2Csize_12%2Ctext_SmF2YSA4IEd1IFA%3D%2Ccolor_FFFFFF%2Cshadow_50%2Ct_80%2Cg_se%2Cx_10%2Cy_10"></p>
  <p data-lake-id="u647dc679" id="u647dc679"><span data-lake-id="ueefb7d9d" id="ueefb7d9d">​</span><br></p>
  <p data-lake-id="ua2bb96a4" id="ua2bb96a4"><span data-lake-id="ub9929639" id="ub9929639">有些特殊场景，如黑名单场景，本地缓存也会用bloom filter来充当，因为bloom filter是有假阳性的特性的，所以命中后需要在查一次分布式缓存，如果没命中则直接返回。</span></p>
  <p data-lake-id="u12749d44" id="u12749d44" style="text-align: center"><img src="https://cdn.nlark.com/yuque/0/2023/png/5378072/1690547156212-e31ee3a2-d497-4cd9-8cd8-844aebb992e3.png?x-oss-process=image%2Fwatermark%2Ctype_d3F5LW1pY3JvaGVp%2Csize_14%2Ctext_SmF2YSA4IEd1IFA%3D%2Ccolor_FFFFFF%2Cshadow_50%2Ct_80%2Cg_se%2Cx_10%2Cy_10"></p>
  <p data-lake-id="u48dcf681" id="u48dcf681" style="text-align: center"><br></p>
  <p data-lake-id="u889390af" id="u889390af" style="text-align: left"><span data-lake-id="ueda08ef1" id="ueda08ef1">简单代码逻辑如下：</span></p>
  <p data-lake-id="uc0927efd" id="uc0927efd" style="text-align: left"><span data-lake-id="u008b4a29" id="u008b4a29">​</span><br></p>
  <pre lang="java"><code>
public String query(String key){

	String localResult = localCache.get(key);

	if(localResult == null){
  	String remoteResult = remoteCache.get(key);
  	if(remoteResult != null){
    	localCache.put(remoteResult);
    }
  }

	return localResult;

}
</code></pre>
  <p data-lake-id="u313874f5" id="u313874f5"><span data-lake-id="ud3d83d95" id="ud3d83d95">​</span><br></p>
  <h1 data-lake-id="OycXt" id="OycXt"><span data-lake-id="u76d27cdf" id="u76d27cdf">扩展知识</span></h1>
  <p data-lake-id="u681e633f" id="u681e633f"><br></p>
  <h2 data-lake-id="NOMvm" id="NOMvm"><span data-lake-id="u38575852" id="u38575852">一致性问题</span></h2>
  <p data-lake-id="u9b6a0053" id="u9b6a0053"><br></p>
  <p data-lake-id="u36a01e52" id="u36a01e52"><span data-lake-id="u84334ead" id="u84334ead">使用多级缓存，比较大的问题就是一致性如何保证，因为用到了本地缓存，而一个集群中有很多台服务器，每个服务器上面的本地缓存内容都不一样。</span></p>
  <p data-lake-id="u7e9c9756" id="u7e9c9756"><span data-lake-id="u2dfee68d" id="u2dfee68d">​</span><br></p>
  <p data-lake-id="u7d3bddce" id="u7d3bddce"><span data-lake-id="u046b2e1b" id="u046b2e1b">这个是使用本地缓存的最大的劣势了，但是这个问题是在提升性能的情况下不可避免的带来的副作用。</span></p>
  <p data-lake-id="udcdf58a7" id="udcdf58a7"><span data-lake-id="u68913aa5" id="u68913aa5">​</span><br></p>
 </body>
</html>